package entity;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author 杨苏鹤
 * NumberGenerate
 * 分布式唯一编号生成器，通过ip地址的低16位进行区分，所有需要保证集群中机子的ip地址低两位不一样，每秒每台机子最多产生16384个编号，最大可以支持到2242-03-16 20:56:31
 * 64位分布图  从高到低  1 符号位  33 时间戳（秒级） 16 ip地址低两位  14 自增id
 * 2020/1/20 15:06
 */
public  class  NumberGenerate {
    //用于缓存编号，加快编号的获取速度，同时处理并发访问
    private static BlockingQueue<Long> numberBuffer = new LinkedBlockingQueue();
    private static long ip = 0;
    private static AtomicLong index = new AtomicLong(0);
    private static NumberGenerate numberGenerate = null;
    private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

    public NumberGenerate() {
        try {
            InetAddress address = InetAddress.getLocalHost();
            String[] ipAddress = address.getHostAddress().split("\\.");
            long third = Long.valueOf(ipAddress[2]);
            long forth = Long.valueOf(ipAddress[3]);
            ip = (third * 256 + forth) << 14;
            //初始化部分编号，防止开始获取报错，总数10000个
            long currentTimeMillis = System.currentTimeMillis() / 1000;
            for (int i = 0; i < 10000; i++) {
                long sort = index.getAndIncrement() & 16383;
                long number = currentTimeMillis << 30 | ip | sort;
                numberBuffer.add(number);
            }
            //添加编号生成线程，1秒之后再开始生成，防止和初始编号重复
            for (int i = 0; i < 2; i++) {
                pool.scheduleAtFixedRate(new Worker(), 1, 1, TimeUnit.SECONDS);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    public static NumberGenerate getInstance() {
        if (numberGenerate == null) {
            numberGenerate = new NumberGenerate();
        }
        return numberGenerate;
    }

    public synchronized long getNumber() {
        return numberBuffer.poll();
    }

    public static class Worker implements Runnable {
        @Override
        public void run() {
            //如果当前缓存中有超过20000个编号，直接返回
            if (numberBuffer.size() > 20000) {
                return;
            }
            //否则生成8192个编号，总共两个线程 8192*2 = 16384
            long currentTimeMillis = System.currentTimeMillis() / 1000;
            for (int i = 0; i < 8192; i++) {
                long sort = index.getAndIncrement() & 16383;
                long number = currentTimeMillis << 30 | ip | sort;
                numberBuffer.add(number);
            }
        }
    }


}

